import { defineComponent, ref, reactive, watchEffect, computed, provide, createVNode } from 'vue';
import { Value } from '../../inner/Value.js';
import DatePane from './DatePane.js';
import MonthPane from './MonthPane.js';
import MonthRangePane from './MonthRangePane.js';
import DateRangePane from './DateRangePane.js';
import DateTimePane from './DateTimePane.js';
import DateTimeRangePane from './DateTimeRangePane.js';
import dayjs from 'dayjs';
import Dropdown from '../../Dropdown/index.js';
import formFieldRef from '../../use/formFieldRef.js';
import { FeatherCalendar } from 'cui-vue-icons/feather';

const index = /* @__PURE__ */ defineComponent({
  name: 'Datepicker',
  props: {
    disabled: {
      type: Boolean
    },
    theme: {
      type: String
    },
    size: {
      type: String
    },
    clearable: {
      type: Boolean
    },
    type: {
      type: String
    },
    align: {
      type: String
    },
    format: {
      type: String
    },
    modelValue: {
      type: [String, Date, Array],
      default: undefined
    },
    prepend: {
      type: [String, Object]
    },
    header: {
      type: [String, Object]
    },
    footer: {
      type: [String, Object]
    },
    seperator: {
      type: String
    },
    disabledDate: {
      type: Function
    },
    transfer: {
      type: Boolean
    },
    trigger: {
      type: Function
    },
    onChange: {
      type: Function
    },
    maxRange: {
      type: Number
    },
    shortCuts: {
      type: [Function, Object]
    },
    revers: {
      type: Boolean
    },
    placeholder: {
      type: String
    },
    stick: {
      type: Boolean
    },
    asFormField: {
      type: Boolean,
      default: true
    }
  },
  emits: ['change', 'update:modelValue'],
  setup(props, {
    emit
  }) {
    const visible = ref(false);
    const type = props.type ?? 'date';
    const value = formFieldRef(props, emit, props.modelValue ?? (type === 'dateRange' || type === 'dateTimeRange') ? [] : '');
    const v = ref();
    let format = props.format ?? 'YYYY-MM-DD';
    if (type === 'month' || type === 'monthRange') {
      format = props.format ?? 'YYYY-MM';
    }
    if (type === 'dateTime' || type === 'dateTimeRange') {
      format = props.format ?? 'YYYY-MM-DD HH:mm:ss';
    }
    const now = new Date();
    const next = new Date();
    next.setMonth(next.getMonth() + 1);
    const store = reactive({
      currentMonth: [now, next],
      range: [],
      hoverDate: undefined
    });
    const align = props.align ?? 'bottomLeft';
    const seperator = props.seperator || '~';
    watchEffect(() => {
      let val = value.value;
      if (val && val instanceof Array && typeof val[0] === 'function') {
        val = val[0]();
      }
      let currentMonth;
      if (val) {
        if (typeof val === 'string') {
          if (type === 'dateRange' || type === 'monthRange' || type === 'dateTimeRange') {
            const arr = val.split(seperator);
            val = [dayjs(arr[0]).toDate(), dayjs(arr[1]).toDate()];
            const prev = new Date(val[0]);
            const next = new Date(val[1]);
            if (dayjs(prev).format('YYYY-MM') === dayjs(next).format('YYYY-MM')) {
              next.setMonth(next.getMonth() + 1);
            }
            currentMonth = [prev, next];
          } else {
            val = dayjs(val).toDate();
            const prev = new Date(val);
            const next = new Date(val);
            next.setMonth(next.getMonth() + 1);
            currentMonth = [prev, next];
          }
        } else if (val instanceof Date) {
          val = dayjs(val).toDate();
          const prev = new Date(val);
          const next = new Date(val);
          next.setMonth(next.getMonth() + 1);
          currentMonth = [prev, next];
        } else {
          let prev = new Date();
          let next = new Date();
          if (val instanceof Array) {
            if (typeof val[0] === 'string') {
              val[0] = dayjs(val[0]).toDate();
            }
            if (typeof val[1] === 'string') {
              val[1] = dayjs(val[1]).toDate();
            }
            prev = val[0] === undefined ? new Date() : val[0] ? new Date(val[0]) : new Date();
            next = val[1] === undefined ? new Date() : val[1] ? new Date(val[1]) : new Date();
          }
          if (type === 'month' && val instanceof Date) {
            prev = val;
            next = new Date(val);
          }
          if (dayjs(prev).format('YYYY-MM') === dayjs(next).format('YYYY-MM')) {
            next.setMonth(next.getMonth() + 1);
          }
          currentMonth = [prev, next];
        }
        if (type === 'dateRange' || type === 'dateTimeRange') {
          store.range = val;
        }
      } else {
        currentMonth = [now, next];
      }
      // 粘连时根据第一个month往后加一个月
      if (props.stick) {
        currentMonth[1] = new Date(currentMonth[0]);
        currentMonth[1].setMonth(currentMonth[1].getMonth() + 1);
      }
      currentMonth[0].setDate(1);
      currentMonth[1].setDate(1);
      store.currentMonth = currentMonth;
      v.value = val;
    });
    const classList = computed(() => ({
      'cm-date-picker': true,
      [`cm-date-picker-${props.size}`]: props.size,
      'cm-date-picker-disabled': props.disabled,
      'cm-date-picker-clearable': !props.disabled && props.clearable && value.value && value.value.length !== 0
    }));
    const onClear = () => {
      value.value = '';
      if (type === 'dateRange') {
        store.range = [];
      }
      emit('change', '');
    };

    // 点击选择日期
    const onSelectDate = (day, name) => {
      const va = new Date(day);
      if (type === 'month' || type === 'monthRange') {
        va.setDate(1);
        va.setHours(0);
        va.setMinutes(0);
        va.setSeconds(0);
        va.setMilliseconds(0);
      }
      if (type === 'dateTime' || type === 'dateTimeRange') {
        let val = v.value;
        if (type === 'dateTimeRange') {
          val = val && val.length ? val[store.range.length === 1 ? 1 : 0] : store.currentMonth[store.range.length === 1 ? 1 : 0];
        } else {
          val = val ? val : store.currentMonth[store.range.length === 1 ? 1 : 0];
        }
        va.setHours(val.getHours());
        va.setMinutes(val.getMinutes());
        va.setSeconds(val.getSeconds());
      }
      const now = new Date();
      let origin = v.value || (type === 'monthRange' || type === 'dateRange' || type === 'dateTimeRange' ? [now, now] : now);
      if ((type === 'dateRange' || type === 'dateTimeRange') && !origin.length) {
        origin = [];
        origin.push(now);
        origin.push(now);
      }
      let newVal;
      if (name === 'start') {
        newVal = [va, origin[1]];
      } else if (name === 'end') {
        newVal = [origin[0], va];
      } else {
        newVal = va;
      }
      if (newVal instanceof Array && newVal[0].getTime() > newVal[1].getTime()) {
        newVal.reverse();
      }
      // dateRange特殊处理
      if (type === 'dateRange' || type === 'dateTimeRange') {
        const range = store.range;
        let newRange = [];
        // 上次已经选择
        if (range[0] && range[1] || !range[0] && !range[1]) {
          newRange = [va];
          store.hoverDate = new Date(va);
        }
        if (range[0] && !range[1]) {
          if (isOutRange(range[0], va)) {
            return;
          }
          newRange = [range[0], va];
          if (newRange[0].getTime() > newRange[1].getTime()) {
            newRange.reverse();
            // dateTImeRange时需要切换currentMonth的时间
            const tmp = new Date();
            copyHMS(tmp, store.currentMonth[0]);
            copyHMS(store.currentMonth[0], store.currentMonth[1]);
            copyHMS(store.currentMonth[1], tmp);
            store.currentMonth = [...store.currentMonth];
          }
          value.value = newRange;
          if (type === 'dateRange') {
            visible.value = false;
          }
        }
        store.range = newRange;
        return;
      }
      value.value = newVal;
      emit('change', newVal);
      if (type === 'date') {
        visible.value = false;
      }
    };
    const copyHMS = (target, source) => {
      target.setHours(source.getHours());
      target.setMinutes(source.getMinutes());
      target.setSeconds(source.getSeconds());
    };
    const onSelectTime = (time, name) => {
      let val = v.value;
      let month;
      if (name === 'start') {
        month = store.currentMonth[0];
        if (val && val[0]) {
          copyHMS(val[0], time);
          if (val[0].getTime() > val[1].getTime()) {
            val.reverse();
            // dateTImeRange时需要切换currentMonth的时间
            copyHMS(store.currentMonth[0], val[0]);
            copyHMS(store.currentMonth[1], val[1]);
          } else {
            copyHMS(month, time);
          }
          value.value = [...val];
        } else {
          copyHMS(month, time);
        }
      } else if (name === 'end') {
        month = store.currentMonth[1];
        if (val && val[1]) {
          copyHMS(val[1], time);
          if (val[0].getTime() > val[1].getTime()) {
            val.reverse();
            // dateTImeRange时需要切换currentMonth的时间
            copyHMS(store.currentMonth[0], val[0]);
            copyHMS(store.currentMonth[1], val[1]);
          } else {
            copyHMS(month, time);
          }
          value.value = [...val];
        } else {
          copyHMS(month, time);
        }
      } else {
        if (!val) {
          val = new Date();
        }
        copyHMS(val, time);
        month = store.currentMonth[0];
        copyHMS(month, time);
        value.value = new Date(val);
      }
      store.currentMonth = [...store.currentMonth];
    };

    /**
     * 是超出maxRange
     * @param start
     * @param current
     * @returns
     */
    const isOutRange = (start, current) => {
      if (props.maxRange) {
        const ms = start.getTime() - current.getTime();
        const days = Math.abs(ms / 1000 / 60 / 60 / 24);
        if (days > props.maxRange - 1) {
          return true;
        }
      }
      return false;
    };

    // 时间段选择
    const onMouseOver = day => {
      if (store.range && store.range[0]) {
        if (isOutRange(store.range[0], day) && props.maxRange) {
          const end = new Date(store.range[0]);
          const delta = day.getTime() > store.range[0].getTime() ? 1 : -1;
          end.setDate(end.getDate() + (props.maxRange - 1) * delta);
          store.hoverDate = end;
          return;
        }
        store.hoverDate = new Date(day);
      }
    };
    const text = () => {
      const val = v.value;
      if (val) {
        if (typeof val === 'string') {
          return val;
        } else {
          if (type === 'dateRange' || type === 'monthRange' || type === 'dateTimeRange') {
            if (!val[0]) {
              return '';
            }
            return [dayjs(val[0]).format(format), dayjs(val[1]).format(format)].join(seperator);
          }
          return dayjs(val).format(format);
        }
      }
      return '';
    };
    provide('CMDatepickerContext', {
      store,
      onSelectDate,
      onMouseOver,
      visible,
      disabledDate: props.disabledDate,
      onSelectTime,
      stick: props.stick,
      type,
      format
    });
    return () => createVNode("div", {
      "class": classList.value
    }, [createVNode(Dropdown, {
      "modelValue": visible.value,
      "onUpdate:modelValue": $event => visible.value = $event,
      "transfer": props.transfer,
      "align": align,
      "revers": props.revers,
      "trigger": "click",
      "disabled": props.disabled,
      "menu": createVNode("div", {
        "class": "cm-date-picker-wrap"
      }, [props.shortCuts ? createVNode("div", {
        "class": "cm-date-picker-shortcuts"
      }, [typeof props.shortCuts === 'function' ? props.shortCuts() : props.shortCuts]) : null, type === 'date' ? createVNode(DatePane, {
        "value": v.value
      }, null) : null, type === 'month' ? createVNode(MonthPane, {
        "value": v.value
      }, null) : null, type === 'monthRange' ? createVNode(MonthRangePane, {
        "value": v.value
      }, null) : null, type === 'dateRange' ? createVNode(DateRangePane, {
        "value": v.value
      }, null) : null, type === 'dateTime' ? createVNode(DateTimePane, {
        "value": v.value
      }, null) : null, type === 'dateTimeRange' ? createVNode(DateTimeRangePane, {
        "value": v.value
      }, null) : null])
    }, {
      default: () => [!props.trigger ? createVNode(Value, {
        "prepend": props.prepend,
        "text": text(),
        "onClear": onClear,
        "clearable": props.clearable,
        "placeholder": props.placeholder,
        "disabled": props.disabled,
        "size": props.size,
        "icon": createVNode(FeatherCalendar, null, null)
      }, null) : props.trigger && props.trigger()]
    })]);
  }
});

export { index as default };
